#pragma once

#include<iostream>
#include<pthread.h>
#include<vector>
#include<queue>
#include<unistd.h>

//创建一个保存线程信息的结构体
struct ThreadInfo
{
    pthread_t tid;//线程ID
    std::string name;//线程名字
};

template <class T>
class ThreadPool
{
    static const int defaultnum=5;
private:
    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void wakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    bool IsQueueEmpty()
    {
        return _tasks.empty();
    }
    std::string GetThreadName(pthread_t tid)
    {   
        for(const auto& t:_threads)
        {
            if(t.tid==tid)return t.name;
        }
        return "None";
    }
public:
    ThreadPool(int num=defaultnum):_threads(num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }
    static void* HandlerTask(void* args)//成员函数默认第一个参数是this指针，在这里会出现形参不一致问题，所以要加上static
    {
        ThreadPool<T>* tp=static_cast<ThreadPool<T>*>(args);
        std::string name=tp->GetThreadName(pthread_self());
        while(true)
        {
            tp->lock();
            while(tp->IsQueueEmpty())
            {
                tp->ThreadSleep();//没任务，休眠等待
            }

            T t=tp->Pop();

            tp->unlock();

            t.run();//处理任务  任务已经被线程拿到，没别的线程跟它抢了，所以任务的处理不用放在加锁内部
            usleep(10);
            std::cout<<name<<"run,"<<"result:"<<t.GetResult()<<std::endl;
        }
    }
    void Start()
    {
        //构建多线程
        int num=_threads.size();
        for(int i=0;i<num;i++)
        {
            _threads[i].name="thread-"+std::to_string(i+1);//线程的编号从1开始
            pthread_create(&(_threads[i].tid),nullptr,HandlerTask,this);
        }
    }
    T Pop()
    {
        T t=_tasks.front();//取出任务
        _tasks.pop();
        return t;
    }
    void Push(const T& t)
    {
        lock();

        _tasks.push(t);//来任务了

        wakeup();//唤醒那些休眠的线程

        unlock();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
private:
    std::vector<ThreadInfo> _threads;//将构建出来的多个线程保存在vector顺序表里
    std::queue<T> _tasks;//存放主线程所给任务的队列

    pthread_mutex_t _mutex;//给任务队列加锁，维持线程池的同步性
    pthread_cond_t _cond;//没拿到任务的线程需要休眠等待
};